/* do not edit automatically generated by mc from wlists.  */
/* wlists.mod word lists module.

Copyright (C) 2015-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius@glam.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#   include "GStorage.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _wlists_H
#define _wlists_C

#   include "GStorage.h"

typedef struct wlists_performOperation_p wlists_performOperation;

#   define maxNoOfElements 5
typedef struct wlists__T1_r wlists__T1;

typedef struct wlists__T2_a wlists__T2;

typedef wlists__T1 *wlists_wlist;

typedef void (*wlists_performOperation_t) (unsigned int);
struct wlists_performOperation_p { wlists_performOperation_t proc; };

struct wlists__T2_a { unsigned int array[maxNoOfElements-1+1]; };
struct wlists__T1_r {
                      unsigned int noOfElements;
                      wlists__T2 elements;
                      wlists_wlist next;
                    };


/*
   initList - creates a new wlist, l.
*/

extern "C" wlists_wlist wlists_initList (void);

/*
   killList - deletes the complete wlist, l.
*/

extern "C" void wlists_killList (wlists_wlist *l);

/*
   putItemIntoList - places an WORD, c, into wlist, l.
*/

extern "C" void wlists_putItemIntoList (wlists_wlist l, unsigned int c);

/*
   getItemFromList - retrieves the nth WORD from wlist, l.
*/

extern "C" unsigned int wlists_getItemFromList (wlists_wlist l, unsigned int n);

/*
   getIndexOfList - returns the index for WORD, c, in wlist, l.
                    If more than one WORD, c, exists the index
                    for the first is returned.
*/

extern "C" unsigned int wlists_getIndexOfList (wlists_wlist l, unsigned int c);

/*
   noOfItemsInList - returns the number of items in wlist, l.
*/

extern "C" unsigned int wlists_noOfItemsInList (wlists_wlist l);

/*
   includeItemIntoList - adds an WORD, c, into a wlist providing
                         the value does not already exist.
*/

extern "C" void wlists_includeItemIntoList (wlists_wlist l, unsigned int c);

/*
   removeItemFromList - removes a WORD, c, from a wlist.
                        It assumes that this value only appears once.
*/

extern "C" void wlists_removeItemFromList (wlists_wlist l, unsigned int c);

/*
   replaceItemInList - replace the nth WORD in wlist, l.
                       The first item in a wlists is at index, 1.
                       If the index, n, is out of range nothing is changed.
*/

extern "C" void wlists_replaceItemInList (wlists_wlist l, unsigned int n, unsigned int w);

/*
   isItemInList - returns true if a WORD, c, was found in wlist, l.
*/

extern "C" bool wlists_isItemInList (wlists_wlist l, unsigned int c);

/*
   foreachItemInListDo - calls procedure, P, foreach item in wlist, l.
*/

extern "C" void wlists_foreachItemInListDo (wlists_wlist l, wlists_performOperation p);

/*
   duplicateList - returns a duplicate wlist derived from, l.
*/

extern "C" wlists_wlist wlists_duplicateList (wlists_wlist l);

/*
   removeItem - remove an element at index, i, from the wlist data type.
*/

static void removeItem (wlists_wlist p, wlists_wlist l, unsigned int i);


/*
   removeItem - remove an element at index, i, from the wlist data type.
*/

static void removeItem (wlists_wlist p, wlists_wlist l, unsigned int i)
{
  l->noOfElements -= 1;
  while (i <= l->noOfElements)
    {
      l->elements.array[i-1] = l->elements.array[i+1-1];
      i += 1;
    }
  if ((l->noOfElements == 0) && (p != NULL))
    {
      p->next = l->next;
      Storage_DEALLOCATE ((void **) &l, sizeof (wlists__T1));
    }
}


/*
   initList - creates a new wlist, l.
*/

extern "C" wlists_wlist wlists_initList (void)
{
  wlists_wlist l;

  Storage_ALLOCATE ((void **) &l, sizeof (wlists__T1));
  l->noOfElements = 0;
  l->next = NULL;
  return l;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   killList - deletes the complete wlist, l.
*/

extern "C" void wlists_killList (wlists_wlist *l)
{
  if ((*l) != NULL)
    {
      if ((*l)->next != NULL)
        {
          wlists_killList (&(*l)->next);
        }
      Storage_DEALLOCATE ((void **) &(*l), sizeof (wlists__T1));
    }
}


/*
   putItemIntoList - places an WORD, c, into wlist, l.
*/

extern "C" void wlists_putItemIntoList (wlists_wlist l, unsigned int c)
{
  if (l->noOfElements < maxNoOfElements)
    {
      l->noOfElements += 1;
      l->elements.array[l->noOfElements-1] = c;
    }
  else if (l->next != NULL)
    {
      /* avoid dangling else.  */
      wlists_putItemIntoList (l->next, c);
    }
  else
    {
      /* avoid dangling else.  */
      l->next = wlists_initList ();
      wlists_putItemIntoList (l->next, c);
    }
}


/*
   getItemFromList - retrieves the nth WORD from wlist, l.
*/

extern "C" unsigned int wlists_getItemFromList (wlists_wlist l, unsigned int n)
{
  while (l != NULL)
    {
      if (n <= l->noOfElements)
        {
          return l->elements.array[n-1];
        }
      else
        {
          n -= l->noOfElements;
        }
      l = l->next;
    }
  return static_cast<unsigned int> (0);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   getIndexOfList - returns the index for WORD, c, in wlist, l.
                    If more than one WORD, c, exists the index
                    for the first is returned.
*/

extern "C" unsigned int wlists_getIndexOfList (wlists_wlist l, unsigned int c)
{
  unsigned int i;

  if (l == NULL)
    {
      return 0;
    }
  else
    {
      i = 1;
      while (i <= l->noOfElements)
        {
          if (l->elements.array[i-1] == c)
            {
              return i;
            }
          else
            {
              i += 1;
            }
        }
      return l->noOfElements+(wlists_getIndexOfList (l->next, c));
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   noOfItemsInList - returns the number of items in wlist, l.
*/

extern "C" unsigned int wlists_noOfItemsInList (wlists_wlist l)
{
  unsigned int t;

  if (l == NULL)
    {
      return 0;
    }
  else
    {
      t = 0;
      do {
        t += l->noOfElements;
        l = l->next;
      } while (! (l == NULL));
      return t;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   includeItemIntoList - adds an WORD, c, into a wlist providing
                         the value does not already exist.
*/

extern "C" void wlists_includeItemIntoList (wlists_wlist l, unsigned int c)
{
  if (! (wlists_isItemInList (l, c)))
    {
      wlists_putItemIntoList (l, c);
    }
}


/*
   removeItemFromList - removes a WORD, c, from a wlist.
                        It assumes that this value only appears once.
*/

extern "C" void wlists_removeItemFromList (wlists_wlist l, unsigned int c)
{
  wlists_wlist p;
  unsigned int i;
  bool found;

  if (l != NULL)
    {
      found = false;
      p = NULL;
      do {
        i = 1;
        while ((i <= l->noOfElements) && (l->elements.array[i-1] != c))
          {
            i += 1;
          }
        if ((i <= l->noOfElements) && (l->elements.array[i-1] == c))
          {
            found = true;
          }
        else
          {
            p = l;
            l = l->next;
          }
      } while (! ((l == NULL) || found));
      if (found)
        {
          removeItem (p, l, i);
        }
    }
}


/*
   replaceItemInList - replace the nth WORD in wlist, l.
                       The first item in a wlists is at index, 1.
                       If the index, n, is out of range nothing is changed.
*/

extern "C" void wlists_replaceItemInList (wlists_wlist l, unsigned int n, unsigned int w)
{
  while (l != NULL)
    {
      if (n <= l->noOfElements)
        {
          l->elements.array[n-1] = w;
        }
      else
        {
          n -= l->noOfElements;
        }
      l = l->next;
    }
}


/*
   isItemInList - returns true if a WORD, c, was found in wlist, l.
*/

extern "C" bool wlists_isItemInList (wlists_wlist l, unsigned int c)
{
  unsigned int i;

  do {
    i = 1;
    while (i <= l->noOfElements)
      {
        if (l->elements.array[i-1] == c)
          {
            return true;
          }
        else
          {
            i += 1;
          }
      }
    l = l->next;
  } while (! (l == NULL));
  return false;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   foreachItemInListDo - calls procedure, P, foreach item in wlist, l.
*/

extern "C" void wlists_foreachItemInListDo (wlists_wlist l, wlists_performOperation p)
{
  unsigned int i;
  unsigned int n;

  n = wlists_noOfItemsInList (l);
  i = 1;
  while (i <= n)
    {
      (*p.proc) (wlists_getItemFromList (l, i));
      i += 1;
    }
}


/*
   duplicateList - returns a duplicate wlist derived from, l.
*/

extern "C" wlists_wlist wlists_duplicateList (wlists_wlist l)
{
  wlists_wlist m;
  unsigned int n;
  unsigned int i;

  m = wlists_initList ();
  n = wlists_noOfItemsInList (l);
  i = 1;
  while (i <= n)
    {
      wlists_putItemIntoList (m, wlists_getItemFromList (l, i));
      i += 1;
    }
  return m;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void _M2_wlists_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}

extern "C" void _M2_wlists_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
